/*
    Speedbump aka Project Kimbula
    Copyright (C) 2010  Ping Shin Ching

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see http://www.gnu.org/licenses.

	Ping Shin Ching
	righteous.ninja@gmail.com OR ping_sc@hotmail.com
	More information at http://www.tidytutorials.com/p/speedbump.html
 */

/* 
 * A cache with individually lockable entries instead of gatekeepers at 
 * the access functions 
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <assert.h>
#include <errno.h>
#include <map>
#include <string>
#include <iostream>
#include <utility>
#include <algorithm>
#include <list>

#include "simpledoublylinkedlist.h"

typedef enum {
	CACHEENTRY_READY,
	CACHEENTRY_DELETED
}CACHEENTRY_STATUS;


template <typename K>
class operationalattrs{
public:
	operationalattrs():status(CACHEENTRY_READY){}
	pthread_mutex_t lock;
	CACHEENTRY_STATUS status;
	SimpleDoublyLinkedListItem* lsi;
	K indextomap;
};
template<typename K>
class cachekey{
	public:
	~cachekey(){}
	cachekey(K k):key(k){}
	cachekey(){}
	K key;
	operationalattrs<K>* attrs;	
};

template <typename K, typename V>
struct dummydelete{
	bool operator()() { return 1; }
};

template<typename K, typename L>
class keyless{
public:
	bool operator()(const cachekey<K> &k, const cachekey<K> &k2)const {
		L l;	
		if(k.attrs->status==CACHEENTRY_DELETED || k2.attrs->status==CACHEENTRY_DELETED)
			return 1;
		else
			return l(k.key, k2.key);
	}
};


template <typename K, typename V, typename D=dummydelete<K,V>, typename L=std::less<K> >
class cache{
public:
	cache(int);
	~cache();
	int add(std::pair<K,V> &);
	int remove(const K&);
	V* lock(const K&);
	int unlock(const K&);
	int showall(void(*)(K,V));

	/*public only for teting*/SimpleDoublyLinkedList cachelist;
	/*public only for teting*/SimpleDoublyLinkedList deletelist;

private:
	std::map<cachekey<K>, V, keyless<K,L> > cachemap;

	int cachesize;
	int maxcachesize;
};



template <typename K, typename V, typename D, typename L>
cache<K,V,D,L>::cache(int s):maxcachesize(s), cachesize(0){
}

template <typename K, typename V, typename D, typename L>
cache<K,V,D,L>::~cache(){
}

template <typename K, typename V, typename D, typename L>
int cache<K,V,D,L>::add(std::pair<K,V>& p){
	cachekey<K> k(p.first);
	typename std::map<cachekey<K>,V, keyless<K,L> >::iterator it=cachemap.find(k);
	if (it == cachemap.end()){
		k.attrs= new operationalattrs<K>();
		k.attrs->indextomap=p.first;
		cachemap[k]=p.second;
		cachelist.add_end(k.attrs);
	}

}

template <typename K, typename V, typename D, typename L>
int cache<K,V,D,L>::showall(void(*f)(K,V)){
	typename std::map<cachekey<K>,V, keyless<K,L> >::const_iterator it;
	for(it=cachemap.begin(); it !=cachemap.end(); it++)
		f(it->first.key, it->second);

}

template <typename K, typename V, typename D, typename L>
int cache<K,V,D,L>::remove(const K& k){
	cachekey<K> kk(k);
	typename std::map<cachekey<K>,V, keyless<K,L> >::iterator it=cachemap.find(kk);
	if (it != cachemap.end()){
		pthread_mutex_lock(&(it->first.attrs->lock));

		it->first.attrs->status=CACHEENTRY_DELETED;

		pthread_mutex_unlock(&(it->first.attrs->lock));
	}
}

template <typename K, typename V, typename D, typename L>
V* cache<K,V,D,L>::lock(const K& k){
	cachekey<K> kk(k);
	typename std::map<cachekey<K>,V, keyless<K,L> >::iterator it=cachemap.find(kk);
	if (it != cachemap.end()){
		pthread_mutex_lock(&(it->first.attrs->lock));
	}
}

template <typename K, typename V, typename D, typename L>
int cache<K,V,D,L>::unlock(const K& k){
}

/*******************************************************************************
 *
 */

class A{
	public:
		A(char* v){std::cout<<"default constructor"<<std::endl;};
		~A(){std::cout<<"destructor called"<<std::endl;}
		A(){std::cout<<"default constructor"<<std::endl;};
    		A(const A& other){ std::cout<<"copy constructor"<<std::endl;};
        	A& operator = (const A& other){std::cout <<"assignment operator"<<std::endl;}
	void* v;
	int x;


};

class mydelete{

};

void show(const char* x, A* a){
	printf("%s %d\n", x, a->x);
}

struct mylesskey{
	bool operator()(const char* k1 , const char* k2)const {
		return (strcmp(k1,k2) < 0);
	}
};

void debugprint_opattrs(void* a){
	/*
	cacheoperationalattrs<const char*>*aa=(cacheoperationalattrs<const char*>*)a;
	if(aa->indextomap)
		printf("indextomap: %s\n", aa->indextomap);
	else
		printf("indextomap: null\n");
		*/
}

void* mainp(void* v){
	printf("mainp\n");	
	/*
	cache<const char*, A*, mydelete, myless>* pmycache=(cache<const char*, A*, mydelete, myless>*)v;

	sleep(2);
	printf("mainp tyring to lock\n");
	A** a;
	if(!(a=pmycache->lock("hello"))){
		printf("looks like deleted\n");
	}
	pmycache->unlock("hello");
	*/
}

int main (int argv, char** argc){


	
	cache<const char*, A*, mydelete, mylesskey> mycache(1000);	

	A* a = new A("hello");
	a->x=500;	
	std::pair<const char*, A*> y(strdup("c"), a);
	mycache.add(y);
	//cache<mykey, A*, mydeletekey, mylesskey >xman(100);
	mycache.showall(show);
	mycache.lock("c");
}

